package com.tools.web.interceptor.auth;

import com.tools.common.object.Note;
import com.tools.common.thread.Timeunit;
import com.tools.web.interceptor.access.AccessManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;

/**
 * 使用数据库的方式保存 token 和加载用户认证对象
 * 更新方法为空实现，增删改用户数据、角色、权限、路由等都直接更新数据库
 * */
@Note("使用数据库的方式保存 token 和加载用户认证对象" +
        "更新方法为空实现，增删改用户数据、角色、权限、路由等都直接更新数据库")
public final class DBAuthenticationManager extends GenericAuthenticationManager {

    @Note("用数据库来实现 token 的存放与认证功能的 DAO 服务接口")
    private final DBTokenDao dbTokenDao;

    @Note("日志对象")
    private static final Logger LOGGER = LoggerFactory.getLogger(DBAuthenticationManager.class);

    /* **************************************************************************************
     *
     *          构造方法
     *
     * **************************************************************************************
     * */

    public DBAuthenticationManager(DBTokenDao dbTokenDao, AuthSource source, AuthUserService authUserService) {
        this(dbTokenDao, source, authUserService, null);
    }

    public DBAuthenticationManager(DBTokenDao dbTokenDao, AuthSource source,
                                   AuthUserService authUserService, AccessManager accessManager) {
        super(source, authUserService, accessManager);
        this.dbTokenDao = Objects.requireNonNull(dbTokenDao);
    }

    /* **************************************************************************************
     *
     *          功能方法
     *
     * **************************************************************************************
     * */

    @Override
    protected Res getAuthUser(String key, AuthToken token) {
        if(token.ifExpired(this.protected_getTimeunitToBeUsed())) {
            return new Res(true, null);
        }
        String userType = token.getUserType();
        AuthUser authUser = this.getAuthUserService().loadAuthUser(token.getUserId(), userType);
        if(authUser instanceof SingleAuthUser) {
            SingleAuthUser singleAuthUser = (SingleAuthUser) authUser;
            singleAuthUser.setUuid(token.getUuid());
            singleAuthUser.setDeviceTypeId(token.getDeviceTypeId());
            singleAuthUser.setUserType(userType);
        }
        else if(authUser instanceof MultiAuthUser) {
            MultiAuthUser multiAuthUser = (MultiAuthUser) authUser;
            multiAuthUser.setUuid(token.getUuid());
            multiAuthUser.setDeviceTypeId(token.getDeviceTypeId());
            multiAuthUser.setUserType(userType);
        }
        return new Res(true, authUser);
    }

    @Override
    protected void setAuthUser(String key, AuthUser srcAuthUser, AuthToken token) {
        int result = this.dbTokenDao.addToken(key, srcAuthUser, token);
        if(result > 0) {
            LOGGER.info("数据库插入 token: {}-{} 成功，返回结果: {}。认证对象: {}",
                    key, token, result, srcAuthUser);
        } else {
            LOGGER.info("数据库插入 token: {}-{} 失败，返回结果: {}。认证对象: {}",
                    key, token, result, srcAuthUser);
        }
    }

    @Override
    protected void removeAuthUser(String key) {
        int result = this.dbTokenDao.removeToken(key);
        if(result > 0) {
            LOGGER.info("数据库移除 token: {} 成功，返回结果: {}", key, result);
        } else {
            LOGGER.info("数据库移除 token: {} 失败，返回结果: {}", key, result);
        }
    }

    @Override
    protected void updateAuthUser(String key, AuthUser authUser, String separator) {

    }

    @Override
    protected Logger protected_getLogger() {
        return LOGGER;
    }

    @Override
    protected Timeunit protected_getTimeunitToBeUsed() {
        return Timeunit.MILL;
    }

    @Override
    protected void protected_loginOut(String key, String deviceTypeId, String uuid,
                                      AuthUser authUser, String separator) {
        int result = this.dbTokenDao.loginOutToken(key, deviceTypeId, uuid, authUser);
        if(result > 0) {
            LOGGER.info("数据库登出 token: {}:{}:{} 成功，返回结果: {}。认证对象: {}",
                    key, deviceTypeId, uuid, result, authUser);
        } else {
            LOGGER.info("数据库登出 token: {}:{}:{} 失败，返回结果: {}。认证对象: {}",
                    key, deviceTypeId, uuid, result, authUser);
        }
    }
}
